package validate

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"gitverse.ru/synapse/kubelatte/pkg/api/common"
	"gitverse.ru/synapse/kubelatte/pkg/api/v1alpha1"
	"gitverse.ru/synapse/kubelatte/pkg/logs"
	"go.uber.org/zap"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"os"
	"reflect"
	"testing"

	"github.com/ghodss/yaml"
	"github.com/wI2L/jsondiff"
)

func TestMain(m *testing.M) {
	// test context initialization here
	logs.Logger = zap.NewNop()
	os.Exit(m.Run())
}

func loadRule(p string) (*RuleSpec, error) {
	var r RuleSpec
	f, err := os.ReadFile(p)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal(f, &r)
	if err != nil {
		return nil, err
	}

	return &r, nil
}

func TestCheckReverseScope(t *testing.T) {
	rules := []v1alpha1.Item{
		{
			Name:       "disallowed-containers",
			Path:       "spec.containers",
			Value:      ".*",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "disallowed-volumes",
			Path:       "spec.volumes",
			Value:      ".*",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "disallowed-annotations",
			Path:       "metadata.annotations",
			Value:      ".*",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "allowed-volumes-annotations-name",
			Path:       "metadata.annotations|keys(@)",
			Value:      "(agent-inject|micro|annot)",
			Kind:       "Pod",
			ApiVersion: "v1",
		},
	}
	type args struct {
		data  common.ARFields
		rules []v1alpha1.Item
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			name: "check-valid-rule",
			args: args{
				data: common.ARFields{
					Kind:      metav1.GroupVersionKind{Kind: "Pod", Version: "v1"},
					Operation: "CREATE",
					Object: map[string]interface{}{
						"metadata": map[string]interface{}{
							"annotation": map[string]interface{}{
								"annot1": "enabled",
								"annot2": "enabled",
							},
						},
						"spec": map[string]interface{}{
							"containers": map[string]interface{}{
								"name":  "container",
								"image": "image",
							},
						},
					},
				},

				rules: []v1alpha1.Item{rules[2]},
			},
			wantErr: false,
		},
		{
			name: "check-invalid-rule",
			args: args{
				data: common.ARFields{
					Kind:      metav1.GroupVersionKind{Kind: "Pod", Version: "v1"},
					Operation: "CREATE",
					Object: map[string]interface{}{
						"metadata": map[string]interface{}{
							"annotations": map[string]interface{}{
								"annot1": "enabled",
								"key":    "micro",
							},
						},
						"spec": map[string]interface{}{
							"containers": map[string]interface{}{
								"name":  "container",
								"image": "image",
							},
						},
					},
				},
				rules: []v1alpha1.Item{rules[3]},
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := ValidateResource(tt.args.data.Object, tt.args.data, tt.args.rules); (err != nil) != tt.wantErr {
				t.Errorf("ValidateResource() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestCheckScope(t *testing.T) {
	rules := []v1alpha1.Item{
		{
			Name:       "allowed-containers",
			Path:       "spec.containers",
			Value:      ".*",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "allowed-volumes",
			Path:       "spec.volumes",
			Value:      ".*",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "allowed-annotations",
			Path:       "metadata.annotations",
			Value:      ".*",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "allowed-name",
			Path:       "metadata.name",
			Value:      ".*",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "disallowed-volumes-hostPath",
			Path:       "spec.volumes[*].hostPath",
			Value:      "^$",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "disallowed-volumes-secret",
			Path:       "spec.volumes[*].secret",
			Value:      "^$",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "disallowed-env-secret",
			Path:       "spec.containers[*].env[*].valueFrom.secretKeyRef",
			Value:      "^$",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "disallowed-envFrom-secret",
			Path:       "spec.containers[*].envFrom[*].secretRef",
			Value:      "^$",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "allowed-volumes-configmap-name",
			Path:       "spec.containers[?name==\"test1\"].image",
			Value:      "imagefromtemp",
			Kind:       "Pod",
			ApiVersion: "v1",
		}, {
			Name:       "allowed-volumes-annotations-name",
			Path:       "metadata.annotations|keys(@)",
			Value:      "(agent-inject|micro|annot)",
			Kind:       "Pod",
			ApiVersion: "v1",
		},
	}
	type args struct {
		data  map[string]interface{}
		rules []v1alpha1.Item
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			name: "check-valid-rule",
			args: args{
				data: map[string]interface{}{
					"metadata": map[string]interface{}{
						"annotations": map[string]interface{}{
							"annot1": "enabled",
							"annot2": "enabled",
						},
					},
				},
				rules: []v1alpha1.Item{rules[2]},
			},
			wantErr: false,
		},
		{
			name: "check-without-valid-rule",
			args: args{
				data: map[string]interface{}{
					"metadata": map[string]interface{}{
						"annotations": map[string]interface{}{
							"annot1": "enabled",
							"micro":  "enabled",
						},
					},
				},
				rules: rules,
			},
			wantErr: false,
		},
		{
			name: "check-with-empty-key-in-map",
			args: args{
				data: map[string]interface{}{
					"metadata": map[string]interface{}{
						"annotations": map[string]interface{}{
							"":        "enabled",
							"microoo": "enabled",
						},
					},
				},
				rules: rules,
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := CheckScope(tt.args.data, tt.args.rules); (err != nil) != tt.wantErr {
				t.Errorf("CheckScope() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestConvPatch2JSON_ConvertAddToReplace(t *testing.T) {

	type args struct {
		pod1 corev1.Pod
		pod2 corev1.Pod
	}
	tests := []struct {
		name string
		args args
		want jsondiff.Operation
	}{
		{
			name: "add to  replace string",

			args: args{

				pod1: corev1.Pod{},
				pod2: corev1.Pod{
					ObjectMeta: metav1.ObjectMeta{
						Name: "Test Pod",
					},
				},
			},
			want: jsondiff.Operation{
				Type:  "replace",
				Path:  "/metadata/name",
				Value: "Test Pod",
			},
		},
		{
			name: "add to  replace map",

			args: args{

				pod1: corev1.Pod{
					ObjectMeta: metav1.ObjectMeta{
						Name: "Test Pod",
					},
				},
				pod2: corev1.Pod{
					ObjectMeta: metav1.ObjectMeta{
						Name: "Test Pod",
						Annotations: map[string]string{
							"map": "annot",
						},
					},
				},
			},
			want: jsondiff.Operation{
				Type:  "replace",
				Path:  "/metadata/annotations/map",
				Value: "annot",
			},
		},
		{
			name: "add to  replace slice",

			args: args{

				pod1: corev1.Pod{
					ObjectMeta: metav1.ObjectMeta{
						Name: "Test Pod",
					},
					Spec: corev1.PodSpec{
						Containers: []corev1.Container{
							{
								Resources: corev1.ResourceRequirements{},
							},
						},
					},
				},
				pod2: corev1.Pod{
					ObjectMeta: metav1.ObjectMeta{
						Name: "Test Pod",
					},
					Spec: corev1.PodSpec{
						Containers: []corev1.Container{
							{
								Name:      "container1",
								Resources: corev1.ResourceRequirements{},
							},
						},
					},
				},
			},
			want: jsondiff.Operation{
				Type:  "replace",
				Path:  "/spec/containers/0/name",
				Value: "container1",
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			patch, err := jsondiff.Compare(tt.args.pod1, tt.args.pod2)

			if err != nil {
				t.Fail()
			}

			got := ConvertAddToReplace(patch[0])[0]
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("GetConvertor() = %v, want %v", got, tt.want)
			}

		})
	}
}

func TestConvPatch2JSON_ConvertJSON(t *testing.T) {
	//rule := v1alpha1.ScopeSpec{
	//	Type: Validation,
	//	Items: []v1alpha1.Item{
	//	{
	//		Name: "allowed-annotations",
	//		Path: "metadata.annotations",
	//		Values: ".*",
	//		Kind: "Pod",
	//		ApiVersion: "v1",
	//	},
	//}}
	//
	//
	//rule, err := loadRule("../../testdata/configs/good_conf_dir_with_correct_configs/helmcharts-demo_kubelatte-validation_rule.yaml")
	//if err != nil {
	//	t.Error(err)
	//}

	type args struct {
		operation jsondiff.Operation
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			name: "Convert path to json",
			args: args{
				operation: jsondiff.Operation{
					Type:  "add",
					Path:  "/test/path",
					Value: "ok",
				},
			},
			want: []byte("{\"test\":{\"path\":\"ok\"}}"),
		},
		{
			name: "Convert path to json with hyfen",
			args: args{
				operation: jsondiff.Operation{
					Type:  "add",
					Path:  "/test/path/-",
					Value: "ok",
				},
			},
			want: []byte("{\"test\":{\"path\":[\"ok\"]}}"),
		},
		{
			name: "Convert path to json replace",
			args: args{
				operation: jsondiff.Operation{
					Type:  "replace",
					Path:  "/test/path",
					Value: "ok",
				},
			},
			want: []byte("{\"test\":{\"path\":\"ok\"}}"),
		},
		{
			name: "Convert path to json replace with hyfen",
			args: args{
				operation: jsondiff.Operation{
					Type:  "add",
					Path:  "/test/path/-",
					Value: "ok",
				},
			},
			want: []byte("{\"test\":{\"path\":[\"ok\"]}}"),
		},
		{
			name: "Convert path to json remove",
			args: args{
				operation: jsondiff.Operation{
					Type:  "remove",
					Path:  "/test/path",
					Value: "ok",
				},
			},
			want: []byte{110, 117, 108, 108},
		},
		{
			name: "Convert path to json remove with hyfen",
			args: args{
				operation: jsondiff.Operation{
					Type:  "remove",
					Path:  "/test/path/-",
					Value: "ok",
				},
			},
			want: []byte{110, 117, 108, 108},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			conv := GetConvertor()
			got := conv.ConvertJSON(tt.args.operation)
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("GetConvertor() = %v, want %v", got, tt.want)
			}

		})
	}
}

func TestIteratorNewLogic(t *testing.T) {
	type args struct {
		elem      interface{}
		rule      v1alpha1.Simple
		isReverse bool
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		{
			name: "allowed-slice",
			args: args{
				elem: []string{"annot1", "annot2"},
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "(annot1|annot2|annot3)",
				},
			},
			want: true,
		},
		{
			name: "allowed-slice-reversed",
			args: args{
				elem: []string{"annot1", "annot2"},
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "(annot1|annot2|annot3)",
				},
				isReverse: true,
			},
			want: true,
		},
		{
			name: "disallowed-slice",
			args: args{
				elem: []string{"annot", "annot2"},
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "(annot1|annot2|annot3)",
				},
			},
			want: false,
		},
		{
			name: "allowed-string",
			args: args{
				elem: "annot1",
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "(annot1|annot2|annot3)",
				},
			},
			want: true,
		},
		{
			name: "allowed-string-reversed",
			args: args{
				elem: "annot1",
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "(annot1|annot2|annot3)",
				},
				isReverse: true,
			},
			want: true,
		},
		{
			name: "disallowed-string",
			args: args{
				elem: "not-annot",
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "(annot1|annot2|annot3)",
				},
			},
			want: false,
		},
		{
			name: "invalid-regexp-string",
			args: args{
				elem: "not-annot",
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "ffff",
				},
			},
			want: false,
		},
		{
			name: "match-regexp-error-string",
			args: args{
				elem: "not-annot",
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "a(b",
				},
			},
			want: false,
		},
		{
			name: "disallowed-type",
			args: args{
				elem: true,
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "a(b",
				},
			},
			want: false,
		},
		{
			name: "allowed-map",
			args: args{
				elem: map[string]string{"annot1": "ONE", "annot2": "TWO"},
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: ".*",
				},
			},
			want: true,
		},
		{
			name: "allowed-map-reversed",
			args: args{
				elem: map[string]string{"annot1": "ONE", "annot2": "TWO"},
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: ".*",
				},
				isReverse: true,
			},
			want: true,
		},
		{
			name: "disallowed-map",
			args: args{
				elem: map[string]string{"annot1": "ONE", "annot2": "TWO"},
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "^$",
				},
			},
			want: false,
		},
		{
			name: "allowed-struct",
			args: args{
				elem: v1alpha1.Item{
					Name:       "1",
					Path:       "2",
					Value:      "3",
					Kind:       "4",
					ApiVersion: "5",
				},
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: ".*",
				},
			},
			want: true,
		},
		{
			name: "disallowed-struct",
			args: args{
				elem: v1alpha1.Item{
					Name:       "1",
					Path:       "2",
					Value:      "3",
					Kind:       "4",
					ApiVersion: "5",
				},
				rule: v1alpha1.Simple{
					Name:  "allowed-volumes-annotations-name",
					Path:  "metadata.annotations|keys(@)",
					Value: "^$",
				},
			},
			want: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Iterator(tt.args.elem, tt.args.rule.Path, tt.args.rule.Value, tt.args.isReverse); got != tt.want {
				t.Errorf("IteratorNewLogic() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestMergeRuleConfigs(t *testing.T) {
	type args struct {
		file    string
		rulecfg *Rules
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			name: "add mutation rule from file",
			args: args{
				file: "../../testdata/configs/good_conf_dir_with_correct_configs_with_imagge_selector_template/rule.yaml",
				rulecfg: &Rules{
					MutationRuleConfig: []v1alpha1.Item{
						{
							Name:       "allowed-containers",
							Path:       "spec.containers",
							Value:      ".*",
							Kind:       "Pod",
							ApiVersion: "v1",
						},
					},
					ValidationRuleConfig: nil,
				},
			},
			wantErr: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			err := MergeRuleConfigs(tt.args.file, tt.args.rulecfg)
			if (err != nil) != tt.wantErr {
				t.Errorf("MergeRuleConfigs() error = %v, wantErr %v", err, tt.wantErr)
			}
			assert.Equal(t, 2, len(tt.args.rulecfg.MutationRuleConfig), "rule added from file")
		})
	}
}

func TestNewRuleConfigs(t *testing.T) {
	type args struct {
		ruleConfigsFile string
	}
	tests := []struct {
		name    string
		args    args
		want    *RuleSpec
		wantErr bool
	}{
		{
			name: "new valid rule config from file",
			args: args{
				ruleConfigsFile: "../../testdata/configs/good_conf_dir_with_correct_configs_with_imagge_selector_template/rule.yaml",
			},
			want: &RuleSpec{
				Type: Mutation,
				Items: []v1alpha1.Item{
					{
						Name:       "allowed-annotations",
						Path:       "metadata.annotations",
						Value:      ".*",
						Kind:       "Pod",
						ApiVersion: "v1",
					},
				},
			},
			wantErr: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := NewRuleConfigs(tt.args.ruleConfigsFile)
			if (err != nil) != tt.wantErr {
				t.Errorf("NewRuleConfigs() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("NewRuleConfigs() got = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestValidator_SetRules(t *testing.T) {
	t.Run("set rule", func(t *testing.T) {
		v := &Validator{
			Rules: []v1alpha1.Item{},
		}

		want := &Validator{
			Rules: []v1alpha1.Item{{
				Name:  "allowed-annotations",
				Path:  "metadata.annotations",
				Value: ".*",
				Kind:  "Pod",
			}},
		}

		if got := v.SetRules([]v1alpha1.Item{{
			Name:  "allowed-annotations",
			Path:  "metadata.annotations",
			Value: ".*",
			Kind:  "Pod",
		}}); !reflect.DeepEqual(got, want) {
			t.Errorf("SetRules() = %v, want %v", got, want)
		}
	})
}

func Test_parse(t *testing.T) {
	type args struct {
		configFilePath string
	}
	var tests []struct {
		name     string
		args     args
		wantRule *[]v1alpha1.Item
		wantErr  bool
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotRule, err := parse(tt.args.configFilePath)
			if (err != nil) != tt.wantErr {
				t.Errorf("parse() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(gotRule, tt.wantRule) {
				t.Errorf("parse() gotRule = %v, want %v", gotRule, tt.wantRule)
			}
		})
	}
}

func Test_checkScopeOldLogic(t *testing.T) {
	type args struct {
		result interface{}
		rule   v1alpha1.Item
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		{
			name: "ok",
			args: args{
				result: []string{"annot", "key"},
				rule: v1alpha1.Item{
					Name:       "disallowed-containers",
					Path:       "spec.containers",
					Value:      ".*",
					Kind:       "Pod",
					ApiVersion: "v1",
				},
			},
			want: false,
		},
		{
			name: "empty res",
			args: args{
				result: nil,
				rule: v1alpha1.Item{
					Name:       "disallowed-containers",
					Path:       "spec.containers",
					Value:      ".*",
					Kind:       "Pod",
					ApiVersion: "v1",
				},
			},
			want: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			assert.Equalf(t, tt.want, validateValue(tt.args.result, tt.args.rule.Path, tt.args.rule.Value, Deny),
				"validateScopeOldLogic(%v, %v, %v)", tt.args.result, tt.args.rule)
		})
	}
}

func Test_checkScopeNewLogic(t *testing.T) {
	type args struct {
		result interface{}
		simple v1alpha1.Simple
		action string
	}
	tests := []struct {
		name   string
		args   args
		result bool
	}{
		{
			name: ".* 1",
			args: args{
				result: []string{"annot", "key"},
				simple: v1alpha1.Simple{
					Name:  "disallowed-containers",
					Path:  "spec.containers",
					Value: ".*",
				},
				action: Deny,
			},
			result: false,
		},
		{
			name: ".* 2",
			args: args{
				result: []string{"annot", "key"},
				simple: v1alpha1.Simple{
					Name:  "disallowed-containers",
					Path:  "spec.containers",
					Value: ".*",
				},
				action: Allow,
			},
			result: true,
		},
		{
			name: "empty res",
			args: args{
				result: nil,
				simple: v1alpha1.Simple{
					Name:  "disallowed-containers",
					Path:  "spec.containers",
					Value: ".*",
				},
				action: Deny,
			},
			result: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			assert.Equalf(t, tt.result, validateValue(tt.args.result, tt.args.simple.Path, tt.args.simple.Value, tt.args.action),
				"validateValue(%v, %v, %v)", tt.args.result, tt.args.simple, tt.args.action)
		})
	}
}

func TestCheckReverseScopeWithRuleField(t *testing.T) {
	type args struct {
		original    map[string]interface{}
		requestData common.ARFields
		items       []v1alpha1.Item
	}
	tests := []struct {
		name    string
		args    args
		wantErr assert.ErrorAssertionFunc
	}{
		{
			name: "denied containers in AR",
			args: args{
				requestData: common.ARFields{
					Kind: metav1.GroupVersionKind{
						Group:   "",
						Version: "v1",
						Kind:    "Pod",
					},
					Namespace: "",
					UserInfo:  common.ARUserInfo{},
					Operation: "CREATE",
					OldObject: nil,
					Object: map[string]interface{}{
						"metadata": map[string]interface{}{
							"annotation": map[string]interface{}{
								"annot1": "enabled",
								"annot2": "enabled",
							},
						},
						"spec": map[string]interface{}{
							"containers": []map[string]interface{}{{
								"name":  "some container",
								"image": "image",
							},
							},
						},
					},
				},
				items: []v1alpha1.Item{
					{
						Name:       "container-name",
						Match:      v1alpha1.Match{},
						ApiVersion: "v1",
						Kind:       "Pod",
						Path:       "",
						Value:      "",
						Rule: v1alpha1.Rule{Simples: []v1alpha1.Simple{{
							Name:    "container-name",
							Path:    "spec.containers[].name",
							Value:   "some container",
							Action:  Deny,
							Message: "lalala lululu",
						}}},
					},
				},
			},
			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
				assert.True(t, err != nil)
				return err != nil
			},
		},
		{
			name: "allowed containers in AR",
			args: args{
				requestData: common.ARFields{
					Kind: metav1.GroupVersionKind{
						Group:   "",
						Version: "v1",
						Kind:    "Pod",
					},
					Namespace: "",
					UserInfo:  common.ARUserInfo{},
					Operation: "CREATE",
					OldObject: nil,
					Object: map[string]interface{}{
						"metadata": map[string]interface{}{
							"annotation": map[string]interface{}{
								"annot1": "enabled",
								"annot2": "enabled",
							},
						},
						"spec": map[string]interface{}{
							"containers": []map[string]interface{}{{
								"name":  "some container",
								"image": "image",
							},
							},
						},
					},
				},
				items: []v1alpha1.Item{
					{
						Name:       "container-name",
						Match:      v1alpha1.Match{},
						ApiVersion: "v1",
						Kind:       "Pod",
						Path:       "",
						Value:      "",
						Rule: v1alpha1.Rule{Simples: []v1alpha1.Simple{{
							Name:    "container-name",
							Path:    "spec.containers[].name",
							Value:   "some container",
							Action:  Allow,
							Message: "lalala lululu",
						}}},
					},
				},
			},
			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
				assert.True(t, err == nil)
				return err == nil
			},
		},
		{
			name: "allowed containers not in AR",
			args: args{
				requestData: common.ARFields{
					Kind: metav1.GroupVersionKind{
						Group:   "",
						Version: "v1",
						Kind:    "Pod",
					},
					Namespace: "",
					UserInfo:  common.ARUserInfo{},
					Operation: "CREATE",
					OldObject: nil,
					Object: map[string]interface{}{
						"metadata": map[string]interface{}{
							"annotation": map[string]interface{}{
								"annot1": "enabled",
								"annot2": "enabled",
							},
						},
						"spec": map[string]interface{}{
							"containers": []map[string]interface{}{{
								"name":  "some another container",
								"image": "image",
							},
							},
						},
					},
				},
				items: []v1alpha1.Item{
					{
						Name:       "container-name",
						Match:      v1alpha1.Match{},
						ApiVersion: "v1",
						Kind:       "Pod",
						Path:       "",
						Value:      "",
						Rule: v1alpha1.Rule{Simples: []v1alpha1.Simple{{
							Name:    "container-name",
							Path:    "spec.containers[].name",
							Value:   "some container",
							Action:  Allow,
							Message: "lalala lululu",
						}}},
					},
				},
			},
			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
				assert.True(t, err != nil)
				return err != nil
			},
		},
		{
			name: "denied volumes",
			args: args{
				requestData: common.ARFields{
					Kind: metav1.GroupVersionKind{
						Group:   "",
						Version: "v1",
						Kind:    "Pod",
					},
					Namespace: "",
					UserInfo:  common.ARUserInfo{},
					Operation: "CREATE",
					OldObject: nil,
					Object: map[string]interface{}{
						"metadata": map[string]interface{}{
							"annotation": map[string]interface{}{
								"annot1": "enabled",
								"annot2": "enabled",
							},
						},
						"spec": map[string]interface{}{
							"volumes": map[string]interface{}{
								"vol": "lolol",
							},
						},
					},
				},
				items: []v1alpha1.Item{{
					Name:       "disallowed-volumes",
					Path:       "spec.volumes",
					Value:      ".*",
					Kind:       "Pod",
					ApiVersion: "v1",
					Rule: v1alpha1.Rule{Simples: []v1alpha1.Simple{{
						Name:    "disallowed-volumes",
						Path:    "spec.volumes",
						Value:   ".*",
						Action:  Deny,
						Message: "",
					}}},
				},
				},
			},
			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
				assert.True(t, err != nil)
				return err != nil
			},
		},
		{
			name: "denied volumes",
			args: args{
				requestData: common.ARFields{
					Kind: metav1.GroupVersionKind{
						Group:   "",
						Version: "v1",
						Kind:    "Pod",
					},
					Namespace: "",
					UserInfo:  common.ARUserInfo{},
					Operation: "CREATE",
					OldObject: nil,
					Object: map[string]interface{}{
						"metadata": map[string]interface{}{
							"annotation": map[string]interface{}{
								"annot1": "enabled",
								"annot2": "enabled",
							},
						},
						"spec": map[string]interface{}{
							"volumes": map[string]interface{}{
								"vol": "lolol",
							},
						},
					},
				},
				items: []v1alpha1.Item{{
					Name:       "disallowed-volumes",
					Path:       "spec.volumes",
					Value:      ".*",
					Kind:       "Pod",
					ApiVersion: "v1",
					Rule: v1alpha1.Rule{Simples: []v1alpha1.Simple{{
						Name:    "disallowed-volumes",
						Path:    "spec.volumes",
						Value:   ".*",
						Action:  Deny,
						Message: "",
					}}},
				},
				},
			},
			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
				assert.True(t, err != nil)
				return err != nil
			},
		},
	}

	for _, tt := range tests {

		t.Run(tt.name, func(t *testing.T) {
			err := ValidateResource(tt.args.original, tt.args.requestData, tt.args.items)
			tt.wantErr(t, err, fmt.Sprintf("ValidateResource(%v, %v, %v)", tt.args.original, tt.args.requestData, tt.args.items))
		})
	}
}

func TestValidateResourceRego(t *testing.T) {
	type args struct {
		original    map[string]interface{}
		requestData common.ARFields
		items       []v1alpha1.Item
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			name: "must be false cause empty object and simples",
			args: args{
				original:    nil,
				requestData: common.ARFields{},
				items: []v1alpha1.Item{{Rule: v1alpha1.Rule{
					Rego: v1alpha1.Rego{
						Template:   "lallal",
						Parameters: "{\"map\": \"string\"}",
					},
				}}},
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := ValidateResource(tt.args.original, tt.args.requestData, tt.args.items); (err != nil) != tt.wantErr {
				t.Errorf("CheckScope() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}
